package com.li.utils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import net.sf.json.JSONObject;

import org.apache.log4j.Logger;

import com.li.menu.Menu;
import com.li.token.AccessToken;
import com.li.user.WxUsers;


/** 
 * 公众平台通用接口工具类 
 *  
 * @author liandyao 
 * @date 2016年1月22日 
 */  
public class WeixinUtil {  

	private static Logger log = Logger.getLogger(WeixinUtil.class);  

	/** 
	 * 发起https请求并获取结果 
	 *  
	 * @param requestUrl 请求地址 
	 * @param requestMethod 请求方式（GET、POST） 
	 * @param outputStr 提交的数据 
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
	 */  
	public static JSONObject httpRequest1(String requestUrl, String requestMethod, String outputStr) {  
		JSONObject jsonObject = null;  
		StringBuffer buffer = new StringBuffer();  
		try {  
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化  
			TrustManager[] tm = { new MyX509TrustManager() };  
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
			sslContext.init(null, tm, new java.security.SecureRandom());  
			// 从上述SSLContext对象中得到SSLSocketFactory对象  
			SSLSocketFactory ssf = sslContext.getSocketFactory();  

			URL url = new URL(requestUrl);  
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
			httpUrlConn.setSSLSocketFactory(ssf);  

			httpUrlConn.setDoOutput(true);  
			httpUrlConn.setDoInput(true);  
			httpUrlConn.setUseCaches(false);  
			// 设置请求方式（GET/POST）  
			httpUrlConn.setRequestMethod(requestMethod);  

			if ("GET".equalsIgnoreCase(requestMethod))  
				httpUrlConn.connect();  

			// 当有数据需要提交时  
			if (null != outputStr) {  
				OutputStream outputStream = httpUrlConn.getOutputStream();  
				// 注意编码格式，防止中文乱码  
				outputStream.write(outputStr.getBytes("UTF-8"));  
				outputStream.close();  
			}  

			// 将返回的输入流转换成字符串  
			InputStream inputStream = httpUrlConn.getInputStream();  
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

			String str = null;  
			while ((str = bufferedReader.readLine()) != null) {  
				buffer.append(str);  
			}  
			bufferedReader.close();  
			inputStreamReader.close();  
			// 释放资源  
			inputStream.close();  
			inputStream = null;  
			httpUrlConn.disconnect();  
			jsonObject = JSONObject.fromObject(buffer.toString());  
		} catch (ConnectException ce) {  
			log.error("Weixin server connection timed out.");  
		} catch (Exception e) {  
			log.error("https request error:{}", e);  
		}  
		return jsonObject;  
	}  
	
	/** 
	 * 发起https请求并获取结果 
	 *  
	 * @param requestUrl 请求地址 
	 * @param requestMethod 请求方式（GET、POST） 
	 * @param outputStr 提交的数据 
	 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
	 */  
	public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {  
		JSONObject jsonObject = null;  
		StringBuffer buffer = new StringBuffer();  
		try {  
			if ("GET".equalsIgnoreCase(requestMethod)){
				buffer.append(HttpService.doGet(requestUrl));
				log.info(buffer.toString());
				jsonObject = JSONObject.fromObject(buffer.toString());  
				
			}else{
				buffer.append(HttpService.doPost(requestUrl,outputStr));
				jsonObject = JSONObject.fromObject(buffer.toString());  
			}
			
			
		} catch (ConnectException ce) {  
			log.error("Weixin server connection timed out.");  
		} catch (Exception e) {  
			log.error("https request error:{}", e);  
		}  
		return jsonObject;  
	}  
	
	
	/** 
	 * 发起https请求并获取结果 
	 *  
	 * @param requestUrl 请求地址 
	 * @param requestMethod 请求方式（GET、POST） 
	 * @param outputStr 提交的数据,需要xml字符串 
	 * @return 返回的是XML类型的数据 
	 */  
	public static String httpRequestByXml(String requestUrl, String requestMethod, String outputStr) {  
		 
		StringBuffer buffer = new StringBuffer();  
		try {  
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化  
			TrustManager[] tm = { new MyX509TrustManager() };  
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
			sslContext.init(null, tm, new java.security.SecureRandom());  
			// 从上述SSLContext对象中得到SSLSocketFactory对象  
			SSLSocketFactory ssf = sslContext.getSocketFactory();  

			URL url = new URL(requestUrl);  
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
			httpUrlConn.setSSLSocketFactory(ssf);  

			httpUrlConn.setDoOutput(true);  
			httpUrlConn.setDoInput(true);  
			httpUrlConn.setUseCaches(false);  
			// 设置请求方式（GET/POST）  
			httpUrlConn.setRequestMethod(requestMethod);  

			if ("GET".equalsIgnoreCase(requestMethod))  
				httpUrlConn.connect();  

			// 当有数据需要提交时  
			if (null != outputStr) {  
				OutputStream outputStream = httpUrlConn.getOutputStream();  
				// 注意编码格式，防止中文乱码  
				outputStream.write(outputStr.getBytes("UTF-8"));  
				outputStream.close();  
			}  

			// 将返回的输入流转换成字符串  
			InputStream inputStream = httpUrlConn.getInputStream();  
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

			String str = null;  
			while ((str = bufferedReader.readLine()) != null) {  
				buffer.append(str);  
			}  
			bufferedReader.close();  
			inputStreamReader.close();  
			// 释放资源  
			inputStream.close();  
			inputStream = null;  
			httpUrlConn.disconnect();   
		} catch (ConnectException ce) {  
			log.error("Weixin server connection timed out.");  
		} catch (Exception e) {  
			log.error("https request error:{}", e);  
		}  
		return buffer.toString();  
	}  



	// 菜单创建（POST） 限100（次/天）  
	public static String menu_create_url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";  

	/** 
	 * 创建菜单 
	 *  
	 * @param menu 菜单实例 
	 * @param accessToken 有效的access_token 
	 * @return 0表示成功，其他值表示失败 
	 */  
	public static int createMenu(Menu menu, String accessToken) {  
		int result = 0;  

		// 拼装创建菜单的url  
		String url = menu_create_url.replace("ACCESS_TOKEN", accessToken);  
		// 将菜单对象转换成json字符串  
		String jsonMenu = JSONObject.fromObject(menu).toString();  

		//System.out.println("访问密钥："+accessToken);

		System.out.println("菜单JSON:\n"+jsonMenu);
		// 调用接口创建菜单  
		JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);  

		if (null != jsonObject) {  
			if (0 != jsonObject.getInt("errcode")) {  
				result = jsonObject.getInt("errcode");  
				log.error("获取token失败 errcode:{"+jsonObject.getInt("errcode")+"} errmsg:{"+jsonObject.getString("errmsg")+"}");  
				System.out.println(jsonObject.getInt("errcode")+ jsonObject.getString("errmsg"));
			}  
		}  

		return result;  
	}


	/**
	 * 获取access_token的接口地址（GET） 限200（次/天）  
	 */
	public final static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";  

	/** 
	 * 获取access_token 
	 *  
	 * @param appid 凭证 
	 * @param appsecret 密钥 
	 * @return 
	 */  
	public static AccessToken getAccessToken(String appid, String appsecret) {  
		AccessToken accessToken = null;  

		String requestUrl = access_token_url.replace("APPID", appid).replace("APPSECRET", appsecret);  
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  
		// 如果请求成功  
		if (null != jsonObject) {  
			try {  
				accessToken = new AccessToken();   
				accessToken.setToken(jsonObject.getString("access_token"));   
				accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
				
			} catch (Exception e) {  
				accessToken = null;  
				// 获取token失败  
				log.error("获取token失败 errcode:{"+jsonObject.getInt("errcode")+"} errmsg:{"+jsonObject.getString("errmsg")+"}");  
			}  
		}  
		return accessToken;  
	}
	
	/**
	 * 采用http GET方式请求获得jsapi_ticket地址
	 */
	public final static String jsapi_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
	
	/** 
	 * 获取Jsapi_ticket_url
	 *  
	 * @param accessToken 基础信息访问令牌
	 * @return jsapi_ticket
	 */  
	public static String getJsapi_ticket_url(String accessToken) {  
		String jsapi_ticket = null ;
		String requestUrl = jsapi_ticket_url.replace("ACCESS_TOKEN", accessToken);  
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  
		// 如果请求成功  
		if (null != jsonObject) {  
			try {  
				 
				 jsapi_ticket = jsonObject.getString("ticket") ;  
				 //jsonObject.getInt("expires_in") ;  
			} catch (Exception e) {  
				accessToken = null;  
				// 获取token失败  
				log.error("获取jsapi_ticket_url失败 errcode:{"+jsonObject.getInt("errcode")+"} errmsg:{"+jsonObject.getString("errmsg")+"}");  
			}  
		}  
		return jsapi_ticket;  
	}

	/**
	 * 微信授权登陆凭证 
	 */
	public static final String authorization_code_url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
	/**
	 * 获取微信授权登陆凭证 -- 登陆授权的第二步
	 * @param code 回调过来的code
	 * @param state 传过来的state,可以不写
	 * @return
	 */
	public static AccessToken getAccessTokenAuthorization_code(String appid,String appsecret, String code){
		AccessToken accessToken = null;
		String requestUrl = authorization_code_url.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);  
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  
		// 如果请求成功  
		if (null != jsonObject) {  
			try {  
				accessToken = new AccessToken();  
				
				accessToken.setAccessToken(jsonObject.getString("access_token"));
				accessToken.setRefreshToken(jsonObject.getString("refresh_token"));
				accessToken.setOpenid(jsonObject.getString("openid"));
				accessToken.setScope(jsonObject.getString("scope"));
			} catch (Exception e) {  
				accessToken = null;  
				// 获取token失败  
				log.error("获取token失败 errcode:{"+jsonObject.getInt("errcode")+"} errmsg:{"+jsonObject.getString("errmsg")+"}");  
			}  
		}  
		return accessToken ;
	}

	/**
	 * 第三步：刷新access_token（如果需要）
<pre>
由于access_token拥有较短的有效期，当access_token超时后，
可以使用refresh_token进行刷新，refresh_token拥有较长的有效期（7天、30天、60天、90天），
当refresh_token失效的后，需要用户重新授权。
</pre>
	 * @param appid 
	 * @param refresh_token 在第二步时得到的结果
	 * @return
	 */
	public static String refresh_token(String appid,String refresh_token){
		String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN" ;
		String requestUrl = url.replace("APPID", appid).replace("REFRESH_TOKEN", refresh_token);  
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  
		return jsonObject.toString() ;

	}
	
	/**
	 * 第四步：拉取用户信息(需scope为 snsapi_userinfo)

如果网页授权作用域为snsapi_userinfo，则此时开发者可以通过access_token和openid拉取用户信息了。
	 * @param access_token网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
	 * @param openid	用户的唯一标识
	 * @param lang返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语 
	 * @return
	 */
	public static WxUsers getWxUsers(String access_token,String openid){
		String url = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN" ;
		String requestUrl = url.replace("ACCESS_TOKEN", access_token).replace("OPENID", openid); 
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null); 
		System.out.println(jsonObject.toString());
		WxUsers wx = (WxUsers) JSONObject.toBean(jsonObject, WxUsers.class);
		return wx ;
	}
	
	
	/**
	 *  关注关注号之后的基础 拉取用户信息  
	 * @param access_token 基础支持的access_token不同
	 * @param openid	用户的唯一标识
	 * @param lang返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语 
	 * @return
	 */
	public static WxUsers getBaseWxUsers(String openid){
		String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN" ;
		String requestUrl = url.replace("ACCESS_TOKEN", WxConfigure.getAccess_token()).replace("OPENID", openid); 
		JSONObject jsonObject = httpRequest(requestUrl, "GET", null); 
		System.out.println(jsonObject.toString());
		WxUsers wx = (WxUsers) JSONObject.toBean(jsonObject, WxUsers.class);
		return wx ;
	}
	
	
	 
}  